﻿using System.Linq;
using System.Threading;
using EasyComm.Contracts;
using EasyComm.ServiceUnit;
using System.Collections;

namespace EasyComm.SDK.Internal
{
    internal static class NLB
    {
        //private static SystemServiceUnitCollection _systemServiceList = new SystemServiceUnitCollection();

        private static Hashtable _serviceStatus = new Hashtable();

        private static AdminServiceUnit<IAdminNLBContract> _adminInstance;
        private static ReaderWriterLockSlim _adminDiscoverLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
        internal static AdminServiceUnit<IAdminNLBContract> AdminInstance
        {
            get
            {
                try
                {
                    _adminDiscoverLock.EnterReadLock();
                    if (_adminInstance == null)
                    {
                        try
                        {
                            _adminDiscoverLock.ExitReadLock();
                            _adminDiscoverLock.EnterWriteLock();
                            _adminInstance = ServiceContext.GetAdminService();
                            EasyCommContext.Admin.OnNLBAdminServiceChange(_adminInstance, _adminInstance.Status == ServiceStatus.Online ? ServiceAvailabilityType.Online : ServiceAvailabilityType.Offline);

                            if (_adminInstance.Status == ServiceStatus.Online)
                            {
                                ServiceResponse response = _adminInstance.Service.Proxy.Initialize();
                                if (response.Code != 0)
                                {
                                    EasyCommContext.OnLog(null, response.MessageType, response.Message);
                                }
                            }
                        }
                        catch { return null; }
                        finally
                        {
                            _adminDiscoverLock.ExitWriteLock();
                        }
                    }
                    return _adminInstance;
                }
                catch { return null; }
                finally
                {
                    if (_adminDiscoverLock.IsReadLockHeld)
                    {
                        _adminDiscoverLock.ExitReadLock();
                    }
                }
            }
        }

        internal static SystemServiceUnit RouterService
        {
            get
            {
                SystemServiceUnit unit = null;
                if (AdminInstance.Status != ServiceStatus.Online)
                {
                    unit = new SystemServiceUnit(null) { Type = SystemServiceType.NLBRouter, Status = ServiceStatus.NA };
                    EasyCommContext.Admin.OnSystemServiceChange(unit, unit.Status == ServiceStatus.Online ? ServiceAvailabilityType.Online : ServiceAvailabilityType.Offline);
                    return unit;
                }
                unit = AdminInstance.Service.Proxy.GetSystemService(SystemServiceType.NLBRouter);
                if (_serviceStatus[unit.ToString()] == null)
                {
                    _serviceStatus[unit.ToString()] = unit.Status == ServiceStatus.Online ? true : false;
                    EasyCommContext.Admin.OnSystemServiceChange(unit, unit.Status == ServiceStatus.Online ? ServiceAvailabilityType.Online : ServiceAvailabilityType.Offline);
                }
                else
                {
                    EasyCommContext.Admin.OnSystemServiceChange(unit, (bool)_serviceStatus[unit.ToString()] == true ? ServiceAvailabilityType.Online : ServiceAvailabilityType.Offline);
                }
                return unit;
            }
        }

        internal static SystemServiceUnit ProxyService
        {
            get
            {
                SystemServiceUnit unit = null;
                if (AdminInstance.Status != ServiceStatus.Online)
                {
                    unit = new SystemServiceUnit(null) { Type = SystemServiceType.NLBProxy, Status = ServiceStatus.NA };
                    EasyCommContext.Admin.OnSystemServiceChange(unit, unit.Status == ServiceStatus.Online ? ServiceAvailabilityType.Online : ServiceAvailabilityType.Offline);
                    return unit;
                }
                unit = AdminInstance.Service.Proxy.GetSystemService(SystemServiceType.NLBProxy);
                if (_serviceStatus[unit.ToString()] == null)
                {
                    _serviceStatus[unit.ToString()] = unit.Status == ServiceStatus.Online ? true : false;
                    EasyCommContext.Admin.OnSystemServiceChange(unit, unit.Status == ServiceStatus.Online ? ServiceAvailabilityType.Online : ServiceAvailabilityType.Offline);
                }
                else
                {
                    EasyCommContext.Admin.OnSystemServiceChange(unit, (bool)_serviceStatus[unit.ToString()] == true ? ServiceAvailabilityType.Online : ServiceAvailabilityType.Offline);
                }
                return unit;
            }
        }

        public static ServiceContractCollection Contracts
        {
            get { return EasyCommContext.IsActive ? RouterService.Contracts : new ServiceContractCollection(); }
        }

        public static AdminServiceUnitCollection<IAdminSLBContract> SystemLoadBalancerList
        {
            get
            {
                if (AdminInstance == null)
                {
                    return new AdminServiceUnitCollection<IAdminSLBContract>();
                }
                return AdminInstance.Service.Proxy.SLBAdminServiceList;
            }
        }

        public static WorkerServiceUnitCollection WorkerList
        {
            get
            {
                if (AdminInstance == null)
                {
                    return new WorkerServiceUnitCollection();
                }
                return AdminInstance.Service.Proxy.WorkerServiceList;
            }
        }

        //internal static IDictionary<Uri, ServiceType> GetServices()
        //{
        //    Dictionary<Uri, ServiceType> serviceList = new Dictionary<Uri, ServiceType>();
        //    DiscoveryClient discoveryClient = null;
        //    try
        //    {
        //        var binding = new NetTcpBinding(SecurityMode.None);
        //        DiscoveryEndpoint discoveryEndpoint = new DiscoveryEndpoint(binding, new EndpointAddress(NetUtils.GetAvailableLocalEndPoint("NLBDiscovery", "", ProtocolScheme.Tcp)));
        //        discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());

        //        FindCriteria proxyCriteria = new FindCriteria();
        //        if (ServiceConfiguration.OnlineCheckTimeout > 0)
        //        {
        //            proxyCriteria.Duration = new TimeSpan(0, 0, ServiceConfiguration.OnlineCheckTimeout);
        //        }
        //        var results = discoveryClient.Find(proxyCriteria);

        //        foreach (EndpointDiscoveryMetadata endpoint in results.Endpoints)
        //        {
        //            if (endpoint.ContractTypeNames.Count(item => item.Name == "DiscoveryProxy") > 0)
        //            {
        //                serviceList.Add(endpoint.Address.Uri, ServiceType.Proxy);
        //            }
        //            if (endpoint.ContractTypeNames.Count(item => item.Name == "ISimplexDatagramRouter") > 0)
        //            {
        //                serviceList.Add(endpoint.Address.Uri, ServiceType.Router);
        //            }
        //            //if (endpoint.ContractTypeNames.Count(item => item.Name == "IAdminContract") > 0)
        //            //{
        //            //    serviceList.Add(endpoint.Address.Uri, ServiceType.Admin);
        //            //}
        //        }
        //    }
        //    finally
        //    {
        //        if (discoveryClient != null)
        //        {
        //            discoveryClient.Close();
        //        }
        //    }
        //    return serviceList;
        //}
    }
}
